Skip to content

Refactor stratum server leak handling#3876

Open
syntaxjak wants to merge 1 commit into
mimblewimble:stagingfrom
syntaxjak:fix-stratum-leaks
Open

Refactor stratum server leak handling#3876
syntaxjak wants to merge 1 commit into
mimblewimble:stagingfrom
syntaxjak:fix-stratum-leaks

Conversation

@syntaxjak

Copy link
Copy Markdown

Addressing issue: #3867

-Reworked the stratum connection handling into a single ‘handle_connection’ loop using ‘tokio::select!’ To drive reads and writes on the same ‘Frames’ socket.

  • Added an RAII ‘WorkerCleanup’ guard so workers are always removed and connections are closed even on errors.
  • Simplified the accept loop (no async_stream) and now logs peer addresses when workers connect.

@wiesche89
wiesche89 changed the base branch from master to staging June 20, 2026 07:35
@ardocrat ardocrat self-assigned this Jun 20, 2026
@iho

iho commented Jul 9, 2026

Copy link
Copy Markdown

Heads-up: #3889 also targets #3867 with the same structural approach (handle_connection + Drop guard + simpler accept loop).

That PR additionally adds idle timeout, max workers, and bounded write queues for the half-open / reconnect-storm failure mode. Worth coordinating so the two don’t land overlapping refactors without combining the resource bounds.

@wiesche89 wiesche89 assigned wiesche89 and unassigned wiesche89 Jul 22, 2026
@wiesche89
wiesche89 self-requested a review July 22, 2026 17:16

@wiesche89 wiesche89 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this with a miner and additional connection tests. The cleanup works for normal disconnects, but it does not fully solve the reported connection leak yet. I’ve left a few comments on the remaining cases.

Image https://github.com/GetGrin/grim/issues/19

Comment thread .gitignore
wallet/db
.idea/
.vscode/
.venv/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks unrelated to the Stratum change. Could we leave it out of this PR?

outgoing = rx.next() => {
match outgoing {
Some(line) => {
if let Err(e) = framed.send(line).await {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While framed.send() is blocked, the socket is no longer read. In my test, this kept a half closed socket alive, while the previous split reader and writer closed it immediately. Could we keep reads and writes independent?

}

async fn handle_connection(socket: TcpStream, handler: Arc<Handler>) {
let (tx, mut rx) = mpsc::unbounded();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since #3889 is closed, I think the limits should be included here. Idle connections otherwise stay open indefinitely and the unbounded queue can keep growing. Could we add an idle timeout, a connection limit, and a bounded queue?

match listener.accept().await {
Ok((socket, _)) => {
let handler = handler.clone();
tokio::spawn(async move {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make the listener and connection tasks cancellable and keep their handles? That would also make clean start and stop support through the Owner API possible later.


impl Drop for WorkerCleanup {
fn drop(&mut self) {
self.workers.remove_worker(self.worker_id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The worker is removed from the map, but its worker_stats entry remains forever. Could we remove or reuse these entries during cleanup?

}
}

async fn handle_connection(socket: TcpStream, handler: Arc<Handler>) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add lifecycle tests for this? The existing Stratum tests only cover JSON serialization and never reach this code.

}
Err(e) => {
error!("accept error = {:?}", e);
continue;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a short backoff for accept errors? With EMFILE, this loop would otherwise spin and flood the log.

error!("accept error = {:?}", e);
continue;
}
loop {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the last use of async stream. Could we also remove the dependency from servers/Cargo.toml?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants